package com.tiancheng.trade.order.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiancheng.trade.commom.core.data.PageInfo;
import com.tiancheng.trade.commom.core.exception.BusinessException;
import com.tiancheng.trade.commom.core.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.commom.core.utils.JsonUtil;
import com.tiancheng.trade.order.bo.SubOrderBO;
import com.tiancheng.trade.order.bo.SubOrderRefundBO;
import com.tiancheng.trade.order.enums.*;
import com.tiancheng.trade.commom.web.feign.PaymentFeignService;
import com.tiancheng.trade.order.mapper.IntSubOrderMapper;
import com.tiancheng.trade.order.mapper.SubOrderStatusMapper;
import com.tiancheng.trade.order.model.*;
import com.tiancheng.trade.order.model.join.IntSubOrderJoin;
import com.tiancheng.trade.order.service.*;
import com.tiancheng.trade.order.util.ObjectConvertUtil;
import com.tiancheng.trade.order.util.helper.OrderIdHelper;
import com.tiancheng.trade.order.vo.admin.QuerySubOrderVO;
import com.tiancheng.trade.order.vo.admin.res.CouponDetailVO;
import com.tiancheng.trade.order.vo.admin.res.SubOrderDetailResVO;
import com.tiancheng.trade.order.vo.admin.res.SubOrderDetailVO;
import com.tiancheng.trade.order.vo.admin.res.SubOrderResVO;
import com.tiancheng.trade.order.vo.api.ReportOrderStatusVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 项目名称：trade-order
 * 类 名 称：IntSubOrderService
 * 类 描 述：子订单操作
 */
@Slf4j
@Service
public class IntSubOrderServiceImpl implements IntSubOrderService {

    @Resource
    private IntSubOrderMapper intSubOrderMapper;
    @Resource
    private RefundOrdersDetailService refundOrdersDetailService;
    @Resource
    private IntOrderService intOrderService;
    @Resource
    private SubOrderStatusService subOrderStatusService;
    @Resource
    private PaymentFeignService paymentFeignService;
    @Resource
    private OrderIdHelper orderIdHelper;
    @Resource
    private SubOrderStatusMapper subOrderStatusMapper;
    private static final String CURRENCY = "USD";

    @Override
    public int create(List<SubOrderBO> subOrderBOS) throws BusinessException {
        List<IntSubOrder> intSubOrders = subOrderBOS.stream().map(subOrderBO -> {
            IntSubOrder intSubOrder = ObjectConvertUtil.convert(subOrderBO, IntSubOrder.class).get();
            intSubOrder.setSubOrderStatus(OrderStatusEnum.waiting_pay.getCode());
            intSubOrder.setPayAmount(intSubOrder.getSubOrderAmount()-intSubOrder.getDiscount());
            intSubOrder.setCurrency(CURRENCY);
            intSubOrder.setCreatedDt(subOrderBO.getCreateTime());
            intSubOrder.setRefundAmount(0);
            return intSubOrder;
        }).collect(Collectors.toList());

        return intSubOrderMapper.saveBatch(intSubOrders);
    }

    @Override
    public PageInfo<SubOrderResVO> querySubOrderList(QuerySubOrderVO subOrderVO) {
        QueryWrapper<IntSubOrder> query = buildQuery(subOrderVO);
        query.orderByDesc("created_dt");
        PageInfo<IntSubOrder> pageInfo = intSubOrderMapper.find(query, subOrderVO.getCurrentPage(), subOrderVO.getPageSize());
        PageInfo<SubOrderResVO> pageRes = new PageInfo<>();
        List<SubOrderResVO> vos = pageInfo.getList().stream().map(subOrder ->
                ObjectConvertUtil.convert(subOrder, SubOrderResVO.class).get()).collect(Collectors.toList());
        vos.forEach(subOrderResVO -> subOrderResVO.setOrderSourceCN(OrderSourceEnum.getDesc(subOrderResVO.getOrderSource())));
        vos.forEach(subOrderResVO -> subOrderResVO.setSubOrderStatusCN(SubOrderStatusEnum.getDesc(subOrderResVO.getSubOrderStatus())));
        pageRes.setList(vos);
        pageRes.setPagination(pageInfo.getPagination());
        return pageRes;
    }

    private QueryWrapper<IntSubOrder> buildQuery(QuerySubOrderVO subOrderVO) {
        QueryWrapper<IntSubOrder> query = new QueryWrapper<>();
        if (StrUtil.isNotBlank(subOrderVO.getOrderId())) {
            query.eq("order_id", subOrderVO.getOrderId());
        }
        if (StrUtil.isNotBlank(subOrderVO.getSubOrderId())) {
            query.eq("sub_order_id", subOrderVO.getSubOrderId());
        }
        if (StrUtil.isNotBlank(subOrderVO.getOriginalSubOrderId())) {
            query.eq("original_sub_order_id", subOrderVO.getOriginalSubOrderId());
        }
        if (StrUtil.isNotBlank(subOrderVO.getMerchantName())) {
            query.like("merchant_name", subOrderVO.getMerchantName());
        }
        if (StrUtil.isNotBlank(subOrderVO.getProductName())) {
            query.like("product_name", subOrderVO.getProductName());
        }

        if (StrUtil.isNotBlank(subOrderVO.getOrderSource())) {
            query.eq("order_source", subOrderVO.getOrderSource());
        }
        if (StrUtil.isNotBlank(subOrderVO.getSubOrderStatus())) {
            query.eq("sub_order_status", subOrderVO.getSubOrderStatus());
        }
        if (StrUtil.isNotBlank(subOrderVO.getVerificationStatus())) {
            query.eq("verification_status", subOrderVO.getVerificationStatus());
        }
        if (!StringUtils.isEmpty(subOrderVO.getCreateTimeBegin()) && !StringUtils.isEmpty(subOrderVO.getCreateTimeEnd())) {
            query.between(
                    "created_dt",
                    LocalDateTime.of(subOrderVO.getCreateTimeBegin(), LocalTime.of(0, 0, 0)),
                    LocalDateTime.of(subOrderVO.getCreateTimeEnd(), LocalTime.of(23, 59, 59))
            );
        }
        if (subOrderVO.getVerificationTimeBegin() != null && subOrderVO.getVerificationTimeEnd() != null) {
            query.between(
                    "verification_time",
                    LocalDateTime.of(subOrderVO.getVerificationTimeBegin(), LocalTime.of(0, 0, 0)),
                    LocalDateTime.of(subOrderVO.getVerificationTimeEnd(), LocalTime.of(23, 59, 59))
            );
        }
        return query;
    }


    @Override
    public int paid(String orderId, Integer couponAmount) throws BusinessException {

        QueryWrapper<IntSubOrder> conditions = new QueryWrapper<>();
        conditions.eq("order_id", orderId);
        conditions.eq("sub_order_status", OrderStatusEnum.waiting_pay.getCode());
        if (null == couponAmount || couponAmount<=0) {
            // 没有优惠券
            log.info("没有优惠券");
            IntSubOrder updateSubOrder = new IntSubOrder();
            updateSubOrder.setSubOrderStatus(OrderStatusEnum.paid.getCode());
            return intSubOrderMapper.update(updateSubOrder, conditions);
        }
        conditions.orderByAsc("id");
        List<IntSubOrder> subOrders = intSubOrderMapper.selectList(conditions);
        if (CollectionUtils.isNotEmpty(subOrders)) {
            log.info("查询到子订单：{}", JsonUtil.toJsonString(subOrders));
        }
        int sumAmount = subOrders.stream().mapToInt(IntSubOrder::getSubOrderAmount).sum();
        int totalDiscount = 0;
        for (int i = 0; i < subOrders.size(); i++) {
            IntSubOrder subOrder = subOrders.get(i);
            IntSubOrder updateSubOrder = new IntSubOrder();
            if (i == subOrders.size() - 1) {
                updateSubOrder.setDiscount(couponAmount-totalDiscount);
            } else {
                // 1、计算子订单所占总金额的比例，小数点后取10位，然后截取
                // 2、总优惠金额*子订单比例，然后四舍五入取整
                int divide = BigDecimal.valueOf(subOrder.getSubOrderAmount()).
                        divide(BigDecimal.valueOf(sumAmount), 10, BigDecimal.ROUND_DOWN)
                        .multiply(BigDecimal.valueOf(couponAmount)).setScale(0, BigDecimal.ROUND_UP).intValue();
                updateSubOrder.setDiscount(divide);
                totalDiscount += (divide);
            }
            log.info("均摊子订单优惠券金额，子订单：{}，优惠：{}", subOrder.getSubOrderId(), updateSubOrder.getDiscount());
            // 实付金额
            updateSubOrder.setIsCoupon(true);
            updateSubOrder.setPayAmount(subOrder.getSubOrderAmount()-updateSubOrder.getDiscount());
            updateSubOrder.setSubOrderStatus(OrderStatusEnum.paid.getCode());
            QueryWrapper<IntSubOrder> updateConditions = new QueryWrapper<>();
            updateConditions.eq("id", subOrder.getId());
            updateConditions.eq("sub_order_id", subOrder.getSubOrderId());
            updateConditions.eq("order_id", subOrder.getOrderId());
            intSubOrderMapper.update(updateSubOrder, updateConditions);
        }
        return 1;
    }


    @Override
    public List<IntSubOrder> find(String orderId) {
        QueryWrapper<IntSubOrder> conditions = new QueryWrapper<>();
        conditions.in("order_id", orderId);
        return intSubOrderMapper.selectList(conditions);
    }

    @Override
    public List<IntSubOrder> findCanRefund(String orderId, String[] subOrderIds) {
        QueryWrapper<IntSubOrder> conditions = new QueryWrapper<>();
        conditions.eq("order_id", orderId);
        conditions.in("sub_order_id", subOrderIds);
        conditions.orderByAsc("id");
        return intSubOrderMapper.selectList(conditions);
    }

    @Override
    public IntSubOrder findBySubId(String subId) {
        QueryWrapper<IntSubOrder> conditions = new QueryWrapper<>();
        conditions.in("sub_order_id", subId);
        return intSubOrderMapper.selectOne(conditions);
    }

    @Override
    public int refundIng(String[] subOrderIds) {
        QueryWrapper<IntSubOrder> conditions = new QueryWrapper<>();
        conditions.in("sub_order_id", subOrderIds);

        IntSubOrder updateSubOrder = new IntSubOrder();
        updateSubOrder.setRefundStatus(RefundStatusEnum.ing.getCode());
        return intSubOrderMapper.update(updateSubOrder, conditions);
    }

    @Override
    public int refund(List<SubOrderRefundBO> subOrderRefundBOS) {
        return intSubOrderMapper.refund(subOrderRefundBOS);
    }

    @Override
    public List<IntSubOrder> findByOrderId(String orderId) {
        QueryWrapper<IntSubOrder> conditions = new QueryWrapper<>();
        conditions.eq("order_id", orderId);
        return intSubOrderMapper.selectList(conditions);
    }

    private SubOrderStatus querySubOrderStatus(IntSubOrder intSubOrder) {
        QueryWrapper<SubOrderStatus> conditions = new QueryWrapper<>();
        conditions.eq("order_source", intSubOrder.getOrderSource());
        conditions.eq("biz_status", intSubOrder.getBizStatus());
        return subOrderStatusMapper.selectOne(conditions);
    }

    /**
     * 功能描述: 根据子订单号查询详情
     *
     * @param:
     * @return:
     * @auther: LiuDong
     * @date: 10:06 2024/4/2
     */
    @Override
    public SubOrderDetailResVO findSubOrderBySubId(String subId) {
        SubOrderDetailResVO detailBO = new SubOrderDetailResVO();
        QueryWrapper<IntSubOrder> conditions = new QueryWrapper<>();
        conditions.eq("sub_order_id", subId);
        List<Coupon> coupons = null;
        List<RefundOrdersDetail> refundOrdersDetails = null;
        IntOrder order = null;
        List<CouponDetailVO> couponVos = null;
        SubOrderDetailVO orderDetailVO = null;
        SubOrderStatus subOrderStatus = null;
        IntSubOrder intSubOrder = intSubOrderMapper.selectOne(conditions);
        if (null != intSubOrder) {
            orderDetailVO = ObjectConvertUtil.convert(intSubOrder, SubOrderDetailVO.class).get();
            refundOrdersDetails = refundOrdersDetailService.getSubRefund(intSubOrder.getSubOrderId());
            order = intOrderService.get(intSubOrder.getOrderId());
            orderDetailVO.setPayCreateTime(order.getCreatedDt());
            orderDetailVO.setPayTime(order.getPayTime());
            orderDetailVO.setFlowId(order.getFlowId());
            orderDetailVO.setPaymentId(order.getPaymentId());
            orderDetailVO.setCouponNum(0);
            subOrderStatus = querySubOrderStatus(intSubOrder);
        }
        if (null != subOrderStatus) {
            orderDetailVO.setBizStatus(subOrderStatus.getBizStatus());
            orderDetailVO.setBizStatusName(subOrderStatus.getBizStatusName());
        }
        detailBO.setRefundOrdersDetails(refundOrdersDetails);
        if (CollectionUtils.isNotEmpty(coupons)) {
            orderDetailVO.setCouponNum(coupons.size());
            orderDetailVO.setIsCoupon(true);
            couponVos = coupons.stream().map(couponBO ->
                    ObjectConvertUtil.convert(couponBO, CouponDetailVO.class).get()).collect(Collectors.toList());
            couponVos.stream().forEach(couponDetailVO -> couponDetailVO.setIsCoupon(true));
            couponVos.stream().forEach(couponDetailVO -> couponDetailVO.setCouponTypeCN(CouponTypeEnum.getDesc(couponDetailVO.getCouponType())));
            couponVos.stream().forEach(couponDetailVO -> couponDetailVO.setDiscountSourceCN(OrderSourceEnum.getDesc(couponDetailVO.getDiscountSource())));
        }
        orderDetailVO.setSubOrderStatusCN(SubOrderStatusEnum.getDesc(orderDetailVO.getSubOrderStatus()));
        orderDetailVO.setOrderSourceCN(OrderSourceEnum.getDesc(intSubOrder.getOrderSource()));
        detailBO.setSubOrderDetailVO(orderDetailVO);
        detailBO.setCoupons(couponVos);
        return detailBO;
    }

    @Override
    public void statusFlow(String orderId, String[] subOrderId, String bizStatus) throws BusinessException {
        IntOrder order = intOrderService.get(orderId);
        BusinessErrorInfoEnum.ORDER_STATUS_FLOW_NO_DATA.assertNotNull(order);

        QueryWrapper<IntSubOrder> queryConditions = new QueryWrapper<>();
        queryConditions.eq("order_id", orderId);
        if (subOrderId != null && subOrderId.length > 0) {
            queryConditions.in("sub_order_id", subOrderId);
        }
        List<IntSubOrder> intSubOrders = intSubOrderMapper.selectList(queryConditions);

        BusinessErrorInfoEnum.ORDER_STATUS_FLOW_NO_DATA.assertIsTrue(intSubOrders.size() > 0);
        Map<String, String> statusMap = subOrderStatusService.find(order.getOrderSource(), bizStatus);
        BusinessErrorInfoEnum.ORDER_STATUS_FLOW_NO_DATA.assertIsTrue(statusMap != null && statusMap.containsKey(bizStatus));

        // 根据业务侧状态取出订单中心对应的状态值，其中还包括是否核销，格式为SC:1
        String[] values = statusMap.get(bizStatus).split(":");
        // 中台子订单状态
        String subOrderStatus = values[0];
        // 核销状态
        String verification = values[1];

        // 修改子订单状态
        IntSubOrder updateSubOrder = new IntSubOrder();
        updateSubOrder.setSubOrderStatus(subOrderStatus);
        updateSubOrder.setBizStatus(bizStatus);

        for (IntSubOrder intSubOrder : intSubOrders) {
            /*// 如果子订单未核销过，并且业务侧状态流转到核销
            if (order.getPayStatus().equals(OrderPayStatusEnum.paid.getCode()) && intSubOrder.getVerificationTime() == null
                    && "1".equals(verification)) {
                VerificationOrderDTO verificationOrderDTO = new VerificationOrderDTO();
                verificationOrderDTO.setUid(StringUtils.isEmpty(order.getBuyerUid()) ? order.getUid() : order.getBuyerUid());
                verificationOrderDTO.setFlowId(order.getFlowId());
                verificationOrderDTO.setSubOrderId(intSubOrder.getSubOrderId());
                verificationOrderDTO.setAmount(intSubOrder.getPayAmount());
                verificationOrderDTO.setVerificationId(orderIdHelper.getVerificationId(order.getUid()));

            }*/
        }
        intSubOrderMapper.update(updateSubOrder, queryConditions);
    }

    @Override
    public IntSubOrderJoin getWithJoin(String subOrderId) {
        IntSubOrderJoin intSubOrderJoin = intSubOrderMapper.getWithJoin(subOrderId);
        if (null != intSubOrderJoin && CollectionUtils.isNotEmpty(intSubOrderJoin.getCoupons())) {
            intSubOrderJoin.setIsCoupon(true);
        }
        return intSubOrderJoin;
    }

    @Override
    public List<IntSubOrder> find(String orderId, String[] subOrderIds) {
        QueryWrapper<IntSubOrder> conditions = new QueryWrapper<>();
        conditions.eq("order_id", orderId);
        conditions.in("sub_order_id", subOrderIds);
        return intSubOrderMapper.selectList(conditions);
    }


    @Override
    public void reportOrderStatus(ReportOrderStatusVO date) {
        String[] subOrderIds = null;
        if(CollectionUtils.isNotEmpty(date.getSubOrderId())){
            subOrderIds=date.getSubOrderId().toArray(new String[0]);
        }
        this.statusFlow(date.getOrderId(),subOrderIds,date.getBizStatus());
    }

}
